/* -----------------------------------------------------------------------------
 * PROJECT    : lwf_handlers
 * FILE       : ArithmaticsFractionHandler.java
 *
 * HISTORY:
 * Date          Author                        Description
 * ----------------------------------------------------------------------------- 
 * Apr 1, 2011  mycodetalks			       Created
 */
package net.lwf.handler.math.fraction;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;

import lwf.handler.IProcessHandler;
import lwf.handler.ProcessHandler;
import lwf.handler.entities.RadioData;
import lwf.handler.entities.math.SumUtil;
import lwf.handler.helper.DisplayFormatter;
import net.lwf.common.constant.ICommonConstant;
import net.lwf.entity.QuestionInfo;
import net.lwf.handler.constant.IHandlerConstant;
import net.lwf.handler.math.fraction.helper.FractionHandlerHelper;
import net.lwf.jaxb.entity.Fraction;
import net.lwf.jaxb.util.maths.fraction.FractionGenerator;
import net.lwf.jaxb.util.maths.fraction.FractionUtil;
import net.lwf.number.util.RandomNumberGenerator;
import net.lwf.pdf.util.FontUtil;
import net.lwf.pdf.util.PdfPCellUtil;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;

/**
 * Class description goes here
 */
public class ArithmaticsFractionHandler extends ProcessHandler implements
		IProcessHandler {

	private FractionGenerator generator;
	private String operationType;
	
	public ArithmaticsFractionHandler(String grade, String operation, String operationtype, String complexity) {
		this.generator = new FractionGenerator(grade, operation, operationtype, complexity);
		this.operationType = operationtype;
		setOperation(operation); //Check this later as the operation is the operation type
	}
	
	public DisplayFormatter getDisplayFormatter() {
		return null;
	}

	public String getQuestionDesc() {
		return null;
	}

//	public boolean matchAnswer(String useranswer, AttemptedQuestion aq) {
//		String correctedanswer = null;
//		if (useranswer != null && useranswer.trim().length() != 0) {
//			Fraction fraction = null;
//			StringTokenizer stk = new StringTokenizer(useranswer.trim(),
//					ICommonConstant.ONE_SPACE);
//			if (stk.countTokens() == 1) {
//				StringTokenizer stk1 = new StringTokenizer(useranswer.trim(),
//						ICommonConstant.FORWARD_SLASH);
//				if (stk1.countTokens() == 1) {
//					int value = Integer.parseInt(stk1.nextToken());
//					if (value == 0) {
//						fraction = new Fraction(0, 0);
//					} else {
//						fraction = new Fraction(value, 1);
//					}
//				} else {
//					fraction = new Fraction(Integer.parseInt(stk1.nextToken()),
//							Integer.parseInt(stk1.nextToken()));
//				}
//			} else {
//				
//				fraction = FractionUtil.mixedToFraction(useranswer, true);
//			}
//			correctedanswer = fraction.toString();
//		}
//
//		if (correctedanswer.equals(aq.getAnswer())) {
//			return true;
//		}
//		return false;
//	}

	@Override
	public QuestionInfo generateSingle() {
		return this.generateSingle(false);
	}

	@Override
	public List<QuestionInfo> generateMultiple() {
		List<QuestionInfo> questions = new ArrayList<QuestionInfo>();
		int nQuestions = getRows() * getColumns();
		for(int i=0; i<nQuestions; i++) {
			QuestionInfo question = this.generateSingle(true);
			question.setQuestionNumber(i+1);
			questions.add(question);
		}
		return questions;
	}

	@Override
	public void getContent(Document document) throws DocumentException {
	}

	@Override
	public int getRows() {
		return 8;
	}

	@Override
	public int getColumns() {
		return 2;
	}

	@Override
	public boolean isPortrait() {
		return true;
	}

	@Override
	public String getPdfInstructionalText() {
		return null;
	}

	@Override
	public String getPdfNote() {
		return null;
	}
	
	@SuppressWarnings("unchecked")
	public Element processCellData(QuestionInfo question) {
		
		List<Fraction> fractions = (List<Fraction>) question.getQuestionObject();

		PdfPTable table = new PdfPTable(1);
        table.setSpacingBefore(20);

        //Row 1
        PdfPCell cell;
        cell = new PdfPCell(new Phrase("# " + question.getQuestionNumber(), FontUtil.getQuestionNumberFont()));
        cell.setBorder(0);
        table.addCell(cell);
        
        //row 2
        cell = PdfPCellUtil.getEmptyCell(0, 0);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.addElement(this.generatePdfQuestion(fractions));
        table.addCell(cell);
        
        table.completeRow();

		return table;
	}	
	
	private QuestionInfo generateSingle(boolean isMultiple) {
		QuestionInfo qinfo = new QuestionInfo();
		qinfo.setOperation(getOperation());
		List<Fraction> fractions = this.getFractions();
		String answer = null;
		qinfo.setQuestionObject(fractions);
		if(this.operationType.equalsIgnoreCase(IHandlerConstant.ADDITION)) {
			answer = FractionUtil.reduce(FractionUtil.add(fractions)).toString();
		}
		else if(this.operationType.equalsIgnoreCase(IHandlerConstant.SUBTRACTION)) {
			answer = FractionUtil.reduce(FractionUtil.subtract(fractions.get(0), fractions.get(1))).toString();
			
		}
		else if(this.operationType.equalsIgnoreCase(IHandlerConstant.MULTIPLICATION)) {
			answer = FractionUtil.reduce(FractionUtil.multiply(fractions.get(0), fractions.get(1))).toString();
		}
		else {
			answer = FractionUtil.reduce(FractionUtil.divide(fractions.get(0), fractions.get(1))).toString();
		}
		qinfo.setAnswer(answer);
		if(!isMultiple) {
			qinfo.setHtmlQuestion(this.generateHtmlQuestion(fractions));	
			//Setting false radio
			qinfo.setRadioAnswerChoices(this.getRadioAnswers(answer));
			qinfo.setPlaceHolder("Find the value of the following fraction expression.");
		}

		
		return qinfo;		
	}
	
	private List<Fraction> getFractions() {
		//Arrange the fractions in descending order
		List<Fraction> fractions = this.generator.generateArithmaticFractions(false);
	    Comparator comparator = Collections.reverseOrder();
	    Collections.sort(fractions, comparator);
		return fractions;
	}

	private String generateHtmlQuestion(List<Fraction> fractions) {
		StringBuffer sbHtml = new StringBuffer("<table border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" >");
		sbHtml.append("<tr>");
		int nCounter = 1;
		for(Fraction fraction: fractions) {
			
			sbHtml.append("<td>" + fraction.toHtml() + "</td>");
			if(nCounter < fractions.size()) {
				sbHtml.append("<td> &nbsp; </td>");
				sbHtml.append("<td>" + SumUtil.getOperationImageHtml(this.operationType) + "</td>");
				sbHtml.append("<td> &nbsp; </td>");
			}
			nCounter++;
		}
		sbHtml.append("<td> &nbsp; </td>");
		sbHtml.append("<td>" + ICommonConstant.EQUAL_TO + "</td>");
		sbHtml.append("<td> &nbsp; </td>");
		sbHtml.append("<td class=\"question\" > " + ICommonConstant.QUESTION + " </td>");

		sbHtml.append("</tr>");
		sbHtml.append("</table>");
		
		return sbHtml.toString();
		
	}
	
	/**
	 * @TODO refactoring
	 * 
	 * @param answer
	 * @return
	 */
	private List<RadioData> getRadioAnswers(String answer) {
		List<RadioData> rdata = new ArrayList<RadioData>();
		rdata.add(new RadioData(answer, answer));

		int whole = 0;
		boolean onlyFraction = false;
		List<Integer> numerators = null;
		List<Integer> denomenators = null;
		StringTokenizer stk_fraction = null;
		String numerator = null;
		String denomenator = null;
		StringTokenizer stk = new StringTokenizer(answer);
		int tokens = stk.countTokens();
		String aValue = null;
		if(tokens == 1) {
			aValue = stk.nextToken();
			//Check it is a fraction or a whole number
			if(aValue.indexOf(ICommonConstant.FORWARD_SLASH) == -1) {
				whole = Integer.parseInt(aValue);
			}
			else {
				onlyFraction = true;
				stk_fraction = new StringTokenizer(aValue, ICommonConstant.FORWARD_SLASH);
				numerator = stk_fraction.nextToken();
				denomenator = stk_fraction.nextToken();
				numerators = RandomNumberGenerator.generateIntsWithVariance(Integer.parseInt(numerator), 4, 3);
				denomenators = RandomNumberGenerator.generateIntsWithVariance(Integer.parseInt(denomenator), 4, 3);
			}
		}
		else {
			whole = Integer.parseInt(stk.nextToken());
		}
		
		String fraction = null;

		if(tokens > 1) {
			fraction = stk.nextToken();
			stk_fraction = new StringTokenizer(fraction, ICommonConstant.FORWARD_SLASH);
			numerator = stk_fraction.nextToken();
			denomenator = stk_fraction.nextToken();
			numerators = RandomNumberGenerator.generateIntsWithVariance(Integer.parseInt(numerator), 4, 3);
			denomenators = RandomNumberGenerator.generateIntsWithVariance(Integer.parseInt(denomenator), 4, 3);
		}
		
		List<Integer> wholes = null;
		String answer_choice = "";
		int nCounter = 0;
		if(!onlyFraction) {
			wholes = RandomNumberGenerator.generateIntsWithVariance(whole, 4, 3);
			for(Integer value: wholes) {
				answer_choice += value.toString();
				if(numerators != null && denomenators != null) {
					answer_choice += " ";
					int numerator_choice = numerators.get(nCounter).intValue();
					int denomenator_choice = denomenators.get(nCounter).intValue();
					if(numerator_choice/denomenator_choice == 1 || numerator_choice > denomenator_choice) {
						denomenator_choice += numerator_choice;
					}
					Fraction fractioN = new Fraction(numerator_choice, denomenator_choice);
					fractioN = FractionUtil.reduce(fractioN);
					
					answer_choice += fractioN.toFraction();
				}
				rdata.add(new RadioData(answer_choice, answer_choice));
				answer_choice = "";
				nCounter++;
			}
		}
		else {
			for(Integer value: numerators) {
				int numerator_choice = value.intValue();
				int denomenator_choice = denomenators.get(nCounter).intValue();
				if(numerator_choice/denomenator_choice == 1 || numerator_choice > denomenator_choice) {
					denomenator_choice += numerator_choice;
				}
				Fraction fractioN = new Fraction(numerator_choice, denomenator_choice);
				fractioN = FractionUtil.reduce(fractioN);
				
				answer_choice += fractioN.toFraction();
				nCounter++;
				rdata.add(new RadioData(answer_choice, answer_choice));
				answer_choice = "";
			}
		}
		
		Collections.shuffle(rdata);
		
		return rdata;
	}
	
	private PdfPTable generatePdfQuestion(List<Fraction> fractions) {
		int nFractions = fractions.size();
		int cells = nFractions + (nFractions - 1) + 1 + 1;
		            //fraction + operations       + = + ?
		PdfPTable table = new PdfPTable(cells);
		PdfPCell cell;
		int nCounter = 1;
		for(Fraction fraction: fractions) {
	        cell = PdfPCellUtil.getEmptyCell(0, 0);
	        cell.addElement(FractionHandlerHelper.generatePDfTable(fraction));
	        table.addCell(cell);
	        if(nCounter < fractions.size()) {
	        	cell = PdfPCellUtil.getImageCell(getBaseImagePath(), SumUtil.getOperationImagePath(this.operationType));
	        	cell.setBorder(0);
	        	cell.setHorizontalAlignment(Element.ALIGN_CENTER);
	        	cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
	        	table.addCell(cell);
	        	nCounter++;
	        }
		}
		cell = PdfPCellUtil.getCell(ICommonConstant.EQUAL_TO);
    	cell.setHorizontalAlignment(Element.ALIGN_CENTER);
    	cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
		table.addCell(cell);
		
		cell = PdfPCellUtil.getCell(ICommonConstant.QUESTION);
    	cell.setHorizontalAlignment(Element.ALIGN_CENTER);
    	cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
		table.addCell(cell);
		
		
		return table;
	}

}



